msghdr;nlmsghdr;iovec结构体的介绍 | 您所在的位置:网站首页 › 简介struct cmsghdr结构 › msghdr;nlmsghdr;iovec结构体的介绍 |
我们从一个实际的数据包发送的例子入手,来看看其发送的具体流程,以及过程中涉及到的相关数据结构。在我们的虚拟机上发送icmp回显请求包,ping另一台主机172.16.48.1。我们使用系统调用sendto发送这个icmp包。 ssize_t sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen); 系统调用sendto最终调用内核函数 asmlinkage long sys_sendto(int fd, void __user * buff, size_t len, unsigned flags, struct sockaddr __user *addr, int addr_len) sys_sendto构建一个结构体struct msghdr,用于接收来自应用层的数据包 ,下面是结构体struct msghdr的定义: struct msghdr { void *msg_name;// 存数据包的目的地址,网络包指向sockaddr_in //向内核发数据时,指向sockaddr_nl int msg_namelen;// 地址长度 struct iovec *msg_iov; __kernel_size_t msg_iovlen; void *msg_control; __kernel_size_t msg_controllen; unsigned msg_flags; }; 这个结构体的内容可以分为四组。 第一组是msg_name和msg_namelen,记录这个消息的名字,其实就是数据包的目的地址 。msg_name是指向一个结构体struct sockaddr的指针。长度为16: struct sockaddr{ sa_family_t sa_family; char sa_addr[14]; } 所以,msg_namelen的长度为16。需要注意的是,结构体struct sockaddr只在进行参数传递时使用,无论是在用户态还是在内核态,我们都把其强制转化为结构体struct sockaddr_in: strcut sockaddr_in{ sa_family_t sin_family; unsigned short int sin_port; struct in_addr sin_addr; unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) - sizeof(unsigned short int) - sizeof(struct in_addr)]; }; struct in_addr{ __u32 s_addr; } __SOCK_SIZE__的值为16,所以,struct sockaddr中真正有用的数据只有8bytes。在我们的ping例子中,传入到内核的msghdr结构中: msg.msg_name = { sa_family_t = MY_AF_INET, sin_port = 0, sin_addr.s_addr = 172.16.48.1 } msg_msg_namelen = 16。 请求回显icmp包没有目的端地址的端口号。 第二组是msg_iov和msg_iovlen,记录这个消息的内容。msg_iov是一个指向结构体struct iovec的指针,实际上,确切地说,应该是一个结构体strcut iovec的数组 。下面是该结构体的定义: struct iovec{ void __user *iov_base; __kernel_size_t iov_len; }; iov_base指向数据包缓冲区,即参数buff,iov_len是buff的长度。msghdr中允许一次传递多个buff,以数组的形式组织在 msg_iov中,msg_iovlen就记录数组的长度 (即有多少个buff)。在我们的ping程序的实例中: msg.msg_iov = { struct iovec = { iov_base = { icmp头+填充字符'E' }, iov_len = 40 } } msg.msg_len = 1 第三组是msg_control和msg_controllen,它们可被用于发送任何的控制信息,在我们的例子中,没有控制信息要发送。暂时略过。 第四组是msg_flags。其值即为传入的参数flags。raw协议不支持MSG_ OOB 向标志,即带外数据。 向向内核发送msg 时使用msghdr,netlink socket使用自己的消息头nlmsghdr和自己的消息地址sockaddr_nl: struct sockaddr_nl { sa_family_t nl_family; unsigned short nl_pad; __u32 nl_pid; __u32 nl_groups; }; struct nlmsghdr { __u32 nlmsg_len; /* Length of message */ __u16 nlmsg_type; /* Message type*/ __u16 nlmsg_flags; /* Additional flags */ __u32 nlmsg_seq; /* Sequence number */ __u32 nlmsg_pid; /* Sending process PID */ }; 过程如下: struct msghdr msg; memset(&msg, 0, sizeof(msg));msg.msg_name = (void *)&(nladdr);msg.msg_namelen = sizeof(nladdr); {/*初始化一个strcut nlmsghdr结构存,nlmsghdr为netlink socket自己的消息头部,并使iov->iov_base指向在这个结构*/ char buffer[] = "An example message"; struct nlmsghdr nlhdr; nlhdr = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_MSGSIZE)); strcpy(NLMSG_DATA (nlhdr),buffer);//将数据存放在消息头指向的数据地址 nlhdr->nlmsg_len = NLMSG_LENGTH(strlen(buffer)); nlhdr->nlmsg_pid = getpid(); /* self pid */ nlhdr->nlmsg_flags = 0; iov.iov_base = (void *)nlhdr; iov.iov_len = nlh->nlmsg_len; } msg.msg_iov = &iov; msg.msg_iovlen = 1; fd=socket(AF_NETLINK, SOCK_RAW, netlink_type); sendmsg(fd,&msg,0) |
CopyRight 2018-2019 实验室设备网 版权所有 |